package mgr

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.

import (
	"context"
	"errors"

	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/gorms"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/passwords"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/xids"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/gqlgen/mgr/gmodel"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/model"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/pkg/dbconn"
	"gitee.com/shiqiyue/xd-bi/internal/pkg/instance"
	"gorm.io/gorm"
)

func (r *mutationResolver) InsertReportDb(ctx context.Context, req gmodel.InsertReportDbReq) (bool, error) {
	// 验证
	db := gorms.GetDb(ctx, r.Db)
	isNameValid, err := r.ReportDbSrv.IsNameValid(ctx, db, req.Name, nil)
	if err != nil {
		return false, err
	}
	if !isNameValid {
		return false, errors.New("名称已存在")
	}

	// 录入
	var reportDbId = xids.GetXid(ctx)
	password, err := passwords.AesEncryptBase64([]byte(req.Password), []byte(instance.GetConfig().App.DbPasswordPrivateKey))
	if err != nil {
		return false, err
	}
	err = db.Transaction(func(tx *gorm.DB) error {
		report := &model.ReportDb{
			ReportDbId:      reportDbId,
			Name:            req.Name,
			Host:            req.Host,
			Port:            req.Port,
			DbName:          req.DbName,
			Type:            req.Type,
			Username:        req.Username,
			Password:        password,
			MaxIdleConns:    req.MaxIdleConns,
			MaxOpenConns:    req.MaxOpenConns,
			ConnMaxLifetime: req.ConnMaxLifetime,
		}
		err := r.ReportDbSrv.Insert(ctx, tx, report)
		return err
	})
	if err == nil {
		return true, nil
	}
	return false, err
}

func (r *mutationResolver) UpdateReportDb(ctx context.Context, req gmodel.UpdateReportDbReq) (bool, error) {
	// 验证
	db := gorms.GetDb(ctx, r.Db)
	isNameValid, err := r.ReportDbSrv.IsNameValid(ctx, db, req.Name, &req.ReportDbID)
	if err != nil {
		return false, err
	}
	if !isNameValid {
		return false, errors.New("名称已存在")
	}
	// 录入
	err = db.Transaction(func(tx *gorm.DB) error {
		updateParam := map[string]interface{}{}
		updateParam["name"] = req.Name
		updateParam["host"] = req.Host
		updateParam["port"] = req.Port
		updateParam["db_name"] = req.DbName
		updateParam["type"] = req.Type
		updateParam["username"] = req.Username
		if req.Password != nil {
			password, err := passwords.AesEncryptBase64([]byte(*req.Password), []byte(instance.GetConfig().App.DbPasswordPrivateKey))
			if err != nil {
				return err
			}
			updateParam["password"] = password
		}
		updateParam["max_open_conns"] = req.MaxOpenConns
		updateParam["max_idle_conns"] = req.MaxIdleConns
		updateParam["conn_max_lifetime"] = req.ConnMaxLifetime
		err := r.ReportDbSrv.UpdateByUnionId(ctx, tx, req.ReportDbID, updateParam)
		return err
	})
	if err == nil {
		return true, nil
	}
	return false, err
}

func (r *mutationResolver) DeleteReportDb(ctx context.Context, dbID string) (bool, error) {
	err := r.ReportDbSrv.RemoveByUnionId(ctx, gorms.GetDb(ctx, r.Db), dbID)
	if err != nil {
		return false, err
	}
	return true, err
}

func (r *queryResolver) ReportDbDetail(ctx context.Context, dbID string) (*model.ReportDb, error) {
	db := gorms.GetDb(ctx, r.Db)
	e := &model.ReportDb{}
	err := r.ReportDbSrv.GetByUnionId(ctx, db, dbID, e)
	if err != nil {
		return nil, err
	}
	return e, nil
}

func (r *queryResolver) ReportDbPage(ctx context.Context, req gmodel.ReportDbPageReq) (*gmodel.ReportDbPageResp, error) {
	db := gorms.GetDb(ctx, r.Db)
	var dest []*model.ReportDb
	simpleWhere := &gorms.SimpleWhere{Items: []gorms.SimpleWhereItem{}}
	if req.Name != nil {
		simpleWhere.Items = append(simpleWhere.Items, gorms.SimpleWhereItem{
			Column:  "code",
			Operate: gorms.OPERATE_LIKE,
			Value:   req.Name,
		})
	}
	pageResult, err := r.ReportDbSrv.PageByParams(ctx, db, simpleWhere, &gorms.Param{
		Page:    req.CurrentPage,
		Limit:   req.PageSize,
		OrderBy: []string{"id desc"},
	}, &dest)
	if err != nil {
		return nil, err
	}
	return &gmodel.ReportDbPageResp{
		TotalRecord: pageResult.TotalRecord,
		Records:     dest,
	}, nil
}

func (r *queryResolver) ReportDbList(ctx context.Context) ([]*model.ReportDb, error) {
	db := gorms.GetDb(ctx, r.Db)
	var dest []*model.ReportDb
	err := r.ReportDbSrv.ListByParams(ctx, db, nil, &dest)
	return dest, err
}

func (r *queryResolver) DbTables(ctx context.Context, dbID string) ([]*gmodel.TableInfo, error) {
	db := gorms.GetDb(ctx, r.Db)
	var reportDb model.ReportDb
	err := r.ReportDbSrv.GetByUnionId(ctx, db, dbID, &reportDb)
	if err != nil {
		return nil, err
	}
	conn, err := dbconn.GetConn(ctx, reportDb)
	if err != nil {
		return nil, err
	}
	getTablesSql := `
SELECT
	t.tablename AS Name
FROM
	pg_tables t
WHERE
	schemaname = CURRENT_SCHEMA ( )
`
	var tableNames []string
	err = conn.Raw(getTablesSql).Find(&tableNames).Error
	if err != nil {
		return nil, err
	}
	getViewsSql := `
SELECT
	viewname as Name
FROM
	pg_views
WHERE
	schemaname = CURRENT_SCHEMA ( )
`
	var viewNames []string
	err = conn.Raw(getViewsSql).Find(&viewNames).Error
	if err != nil {
		return nil, err
	}

	getColumnsSql := `
SELECT A.attname AS Name,
	d.description AS Remark
FROM
	pg_class
	C INNER JOIN pg_attribute A ON A.attrelid = C.oid
	AND A.attnum > 0
	and  A.attname not like '%pg.dropped%'
	left JOIN pg_type T ON A.atttypid = T.oid
	left JOIN pg_description d ON d.objoid = A.attrelid
	AND d.objsubid = A.attnum

WHERE
	C.relname = ?
`
	var tables []*gmodel.TableInfo
	for i := range tableNames {
		table := &gmodel.TableInfo{Name: tableNames[i]}
		var columns []*gmodel.ColumnInfo
		err := conn.Raw(getColumnsSql, tableNames[i]).Find(&columns).Error
		if err != nil {
			return nil, err
		}
		table.Columns = columns
		tables = append(tables, table)
	}
	for i := range viewNames {
		table := &gmodel.TableInfo{Name: viewNames[i] + "(视图)"}
		var columns []*gmodel.ColumnInfo
		err := conn.Raw(getColumnsSql, viewNames[i]).Find(&columns).Error
		if err != nil {
			return nil, err
		}
		table.Columns = columns
		tables = append(tables, table)
	}
	return tables, nil
}
